package com.kk.netty.nio.network.selector;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;

public class WriteServer {
    public static void main(String[] args) throws Exception {
        ServerSocketChannel ssc = ServerSocketChannel.open ( );
        ssc.configureBlocking (false);
        ssc.bind (new InetSocketAddress (8080));

        Selector selector = Selector.open ( );
        ssc.register (selector, SelectionKey.OP_ACCEPT);

        while (true) {
            selector.select ( );
            Iterator<SelectionKey> iter = selector.selectedKeys ( ).iterator ( );

            while (iter.hasNext ( )) {
                SelectionKey key = iter.next ( );
                iter.remove ( );

                if (key.isAcceptable ( )) {
                    SocketChannel sc = ssc.accept ( );
                    sc.configureBlocking (false);
                    SelectionKey scKey = sc.register (selector, SelectionKey.OP_READ);
                    // 1、向客户端发送大量数据
                    StringBuffer sb = new StringBuffer ( );
                    for (int i = 0; i < 3000000; i++) {
                        sb.append ("a");
                    }
                    ByteBuffer buffer = Charset.defaultCharset ( ).encode (sb.toString ( ));

                    // 2、返回值代表实际写入的字节数
                    int write = sc.write (buffer);
                    System.out.println ("实际写入字节:" + write);

                    // 3、判断是否有剩余内容
                    if (buffer.hasRemaining ( )) {
                        // 4、关注可写事件(1+4)
                        // read 1  write 4
                        scKey.interestOps (scKey.interestOps ( ) + SelectionKey.OP_WRITE);
                        // 5、把未写完的数据 挂到 scKey上
                        scKey.attach (buffer);
                    }
                } else if (key.isWritable ( )) {
                    ByteBuffer buffer = (ByteBuffer) key.attachment ( );
                    SocketChannel sc = (SocketChannel) key.channel ( );
                    int write = sc.write (buffer);
                    System.out.println ("实际写入字节:" + write);
                    if (!buffer.hasRemaining ( )) {// 写完了(切换为读模式)
                        key.interestOps (key.interestOps ( ) - SelectionKey.OP_WRITE);
                        // 需要清除 buffer
                        key.attach (null);
                    }
                }
            }
        }
    }
}
